<?php



class File {

	private $directorios     = array();
	public  $list            = NULL;

	public function __construct(){
		if(!is_object($this->list)) $this->list=new stdClass();
	}

	public function __set($var=NULL,$value=NULL){

		$this->list->$var=new stdClass();
		$this->list->$var=$value;
                
	}


	public static function getFilePerms ($archivo) {

		$perms = fileperms($archivo);

		if (($perms & 0xC000) == 0xC000) {

		    // Socket
    			$info = 's';
			} elseif (($perms & 0xA000) == 0xA000) {
    		// Enlace Simbolico
    			$info = 'l';
			} elseif (($perms & 0x8000) == 0x8000) {
    		// Regular
    			$info = '-';
			} elseif (($perms & 0x6000) == 0x6000) {
    		// Bloque especial
    			$info = 'b';
			} elseif (($perms & 0x4000) == 0x4000) {
    		// Directorio
    			$info = 'd';
			} elseif (($perms & 0x2000) == 0x2000) {
    		// Caracter especial
    			$info = 'c';
			} elseif (($perms & 0x1000) == 0x1000) {
    		// Pipe FIFO
    			$info = 'p';
			} else {
    		// Desconocido
    			$info = 'u';
			}

			// Duenyo
				$info .= (($perms & 0x0100) ? 'r' : '-');
				$info .= (($perms & 0x0080) ? 'w' : '-');
				$info .= (($perms & 0x0040) ?
            (($perms & 0x0800) ? 's' : 'x' ) :
            (($perms & 0x0800) ? 'S' : '-'));

			// Group
				$info .= (($perms & 0x0020) ? 'r' : '-');
				$info .= (($perms & 0x0010) ? 'w' : '-');
				$info .= (($perms & 0x0008) ?
            (($perms & 0x0400) ? 's' : 'x' ) :
            (($perms & 0x0400) ? 'S' : '-'));

			// World
				$info .= (($perms & 0x0004) ? 'r' : '-');
				$info .= (($perms & 0x0002) ? 'w' : '-');
				$info .= (($perms & 0x0001) ?
				(($perms & 0x0200) ? 't' : 'x' ) :
				(($perms & 0x0200) ? 'T' : '-'));

			return ($info);

		}

		public static function exists ($file=NULL) {

			if (is_null ($file))
					  throw (new fluxXception ('file name cannot be null!'));

			if (!file_exists ($file))
					  throw (new fluxXception ('File ' . $file . ' doesnt exists'));

			if (!is_readable ($file))
					  throw (new fluxXception ('File ' . $file . 'exists but its not readable by you'));

		}

		
		//The only difference between is_writable is that the file doesnt needs to exist
		//for it to return TRUE. So even if it doesnt exists one could say that is writeable
		//hence the directory is_writable

		public static function isWriteable ($file) {

				  if(is_dir($file)){

							 //Its a directory so it exists
							 //So we can use is_writeable

						if (is_writeable ($file)) {
							clearstatcache();
								  return TRUE;
						}

				  }

				  if (is_file($file)){

						//If the directory is not writeable
						//
	 
						clearstatcache();

						if (!self::isWriteable (dirname($file))) 
							return FALSE;

							$c = file_get_contents ($file);
							if (!@file_put_contents ($c,$file))
								return FALSE;
				 }

				 //if the given file doesnt exists we have to check that the directory is writeable
				  
				 if (!self::isWriteable (dirname($file)))
							 		return FALSE;

				return TRUE;

		}

		public static function write ($file,$contents,$mode=NULL) {

			$dir = dirname ($file);

			if (!is_writable ($dir)) {

				if ($dir == '.')
					$dirMsg = 'current PWD (' . dirname ($_SERVER['SCRIPT_FILENAME']) . ')';

				$message =	'Cannot write ' . $file . ' into ' . $dirMsg . 
								' the given directory is not writable!';

				throw (new Exception ($message));

			}

			(file_exists ($file) && is_null($mode)) ? $mode = 'a' : $mode = 'w';

			$fp = fopen ($file,$mode);
			
			fwrite ($fp,$contents);

			fclose ($fp);

			return (TRUE);

		}

		public static function read ($file=NULL) {

			if (!file_exists ($file))
					  throw (new fluxXception ('The given file ->' . $file . '<- doesnt exists'));

			if (!is_readable ($file))
					  throw (new fluxXception ('File  ->' . $file . '<- is not readable by you'));

			return file_get_contents ($file);

		}

		public static function directoryChecks ($dir=NULL,$writable=FALSE){

			if (is_null ($dir))
				throw (new fluxXception ('Expecting a directory, NULL given'));

			if (!is_dir ($dir))
				throw (new fluxXception ('The given directory ->' . $dir . '<- its not a directory'));

			if (!file_exists($dir))
					  throw (new fluxXception ('Directory ->' . $dir . '<- doesnt exists'));

			if (!is_readable($dir))
					  throw (new fluxXception ('Directory ->' . $dir . '<- is not readable'));

			//Check for writeability ? 

			if ($writable){
					  if (!is_writeable($dir))
					  		throw (new fluxXception ('Directory ->' . $dir . '<- is not writable!'));
			}

			clearstatcache();

		}

		public function addFullMimeType($type=NULL){
				  $this->list->mime->types[]=$type;
		}


		//addPartialMimeType:

		//Its just an alias of addFullMimeType with a simple regex
		//Example add a partial mime type for everything that is 
		//indicated to be an image 
		//$files->addPartialMimeType('image'); #Would output all images
		//$files->addPartialMimeType('text');  #Would output all text files

		public function addPartialMimeType($ptype=NULL){
			$this->addFullMimeType('^'.addslashes($ptype).'/.*');
		}

		public function addExtension($extension=NULL){
				  if(preg_match("#^\.#",$extension)) $extension = substr($extension,1);
				  if(empty($extension)) return FALSE;
				  $this->list->file->extensions[]=$extension;
		}

		public function setMinSize($minsize=NULL){
				  $this->list->file->size['min'] = $minsize;
		}

		//Alias of setMinSize 

		public function lessThan ($minsize=NULL){
				  $this->setMinSize($minsize);
		}

		public function setMaxSize($maxsize=NULL){
				  $this->list->file->size['max'] = $maxsize;
		}

		//Alias of setMaxSize

		public function greaterThan ($maxsize=NULL){
				  $this->setMaxSize($maxSize);
		}

		//Files that only match a given size

		public function equalTo ($size=NULL){
			$this->list->file->size['exact'] = $size;
		}


		private function getProperty ($property,$obj=NULL){
	 		$v   = NULL; 
			$obj = (!is_object($obj)) ? $this->list : $obj;

			foreach ($obj as $key=>$prop){

				if (is_array($property)) 
					if (in_array($key,$property)) return $prop;

				if ($key == $property) return $prop;
				if (is_object($prop)) $v = $this->getProperty($property,$prop);

			}

			return $v;

		}

		private function smallAliases(){
				  return array ('less','small','smaller','minimum','minsize','smallest','lower');
		}

		private function bigAliases(){
				  return array ('more','big','bigger','maxmimum','maxsize','biggest','greatest','greater');
		}

		public function fls ($dir=NULL,$fullPath=NULL) {

			self::directoryChecks ($dir,FALSE); 

			//We dont need to check if the directory is writeable 
			//we need to see if it is_readable 

			$dp   = opendir ($dir);
			$directoryList = array();

			while ($file = readdir ($dp)) {

				//If you didnt wanted to list hidden files or directories, then go on
				if ($this->getProperty('hidden'))
						if(self::isHiddenFile($dir._DS.$file)) continue;


				if ($sizeObj=$this->getProperty('size')){

						  $size = filesize($file);
						  clearstatcache();

						  if ($exObj = $this->getProperty('exact',$sizeObj)){
									 $exact = $this->getProperty('size',$exObj);
									 if($size!==$exact) continue;
						  }

						  $min   = $this->getProperty($this->smallAliases(),$sizeObj);
						  $max   = $this->getProperty($this->bigAliases()  ,$sizeObj);

						  if(isset($min->than)&&isset($max->than))
									 if ($size >= $min->than && $size <= $max->than) continue;

						  if (isset($max->than))
									 if($size < $max->than) continue;

						  if (isset($min->than))
									 if($size > $min->than) continue;

				}
					
				//If you didnt wanted directory listings continue
				if (isset($this->list->directories))
					if (!$this->list->directories) if (is_dir ($dir._DS.$file))                continue;


				//If you only wanted files of extenstion $this->addextension, and the file doesnt match, go on
				if (isset($this->list->file->extensions)){
					if (sizeof($this->list->file->extensions))
						if (!in_array(self::getExtension($dir._DS.$file),$this->list->file->extensions)) continue;
				}

				//If you only wanted files matching a given mime type or a partial 
				//mime type

				if (isset($this->list->mime->types)) {

					if (sizeof($this->list->mime->types)) {
	  
						$finfo = finfo_open(FILEINFO_MIME,$file);
						$mime  = finfo_file($finfo,$file);
						finfo_close($finfo);

						foreach ($this->list->mime->types as $gMime)
								  if (preg_match("#$mime#",$gMime))  $f=TRUE;

						if (!$f) continue;

					}

				//File matched all of the above conditions, go ahead, add the file to directory list
			}

			$directoryList[]=($fullPath) ? $dir._DS.$file : $file;

		}

		closedir($dp);
		return $directoryList;

	}

	public static function getExtension ($file=NULL,$removeDot=TRUE) {

		if ($removeDot)
			return substr(basename($file),strlen(self::removeExtension($file))+1);

			return substr(basename($file),strlen(self::removeExtension($file)));

	}

	public static function removeDuplicated ($files=NULL){

			  $retArray = array();
			  $md5Array = array();

			  foreach ($files as $f) {

						self::exists ($f);

						if (in_array ($md5=md5($f),$md5Array))
							continue;

						$md5Array[] =$md5;
						$retArray[] = $f;

				  }

				  return $retArray;

		}

		public static function removeExtension ($file=NULL) {

			return substr(basename($file),0,-4);
			
		}

		public static function isHiddenFile ($file) {
			return (strpos('.',$file) == 0) ? TRUE : FALSE;
		}


		public static function getFileData ($archivo) {

			$return = NULL;

			$file = basename($archivo);

			if (!is_dir ($archivo)) {

				$temp      = explode ('.',$file);
				$key       = sizeof ($temp) - 1;
				$extension = $temp[$key];


			} else {

				$extension = NULL;	
			}	

			$tipo = shell_exec (escapeshellcmd('file -b ' . $archivo));

			$return['file']      = $file;
			$return['location']  = dirname ($archivo);
			$return['extension'] = $extension;
			$return['tipo']      = $tipo;
			$return['permisos']  = self::getFilePerms ($archivo);
			$return['fecha']     = date ("F d Y H:i:s.", filemtime($archivo));
			$return['size']      = filesize ($archivo);
			clearstatcache();
			return ($return);	

		}

}

?>
